package com.easytouch.core.task;

import android.content.Intent;
import android.os.SystemClock;
import android.util.Pair;


import com.easytouch.core.Configure;
import com.easytouch.core.DriverThread;
import com.easytouch.core.encryption.MD5;
import com.easytouch.core.model.GoodsModel;
import com.easytouch.core.utils.Log;
import com.easytouch.core.utils.OrderGenerator;
import com.easytouch.core.utils.Tools;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;

public class CartTask extends Task {
    public static final String INTENT_CART_MESSAGE = "INTENT_CART_RESULT";
    public static final String EXTRA_CART_CODE = "EXTRA_CART_CODE";
    public static final String EXTRA_CART_MESSAGE = "EXTRA_CART_MESSAGE";
    public static final int CODE_DATA_ERROR = -1;
    public static final int CODE_NET_ERROR = -2;
    public static final int CODE_FINISH = 0;
    public static final int CODE_PAY_OK = 1;
    public static final int CODE_OUT_GOODS = 2;
    public static final int CODE_OUT_ALL_GOODS = 3;

    public static final String PAYTYPE_ALIFACE = "g";

    private static final String KEY = "chujiaokeji2018";
    private Log mLogger = new Log("CartTask.txt");
    private String orderID;
    private ArrayList<GoodsModel> mGoodsArray;

    private String mIp;
    private int mPort = 6001;

    private Socket socket = null;
    private InputStream in = null;
    private OutputStream out = null;

    private static boolean isProcess = false;
    private String mPaytype = "0";
    private String mDetail = "0";

    public CartTask(final String pOrderNo, final ArrayList<GoodsModel> pGoodsArray) {
        super(pOrderNo);
        String order = pOrderNo;
        String[] split = pOrderNo.split("-");
        if (split != null) {
            order = split[0];
        }
        mGoodsArray = new ArrayList<>();
        for (GoodsModel model : pGoodsArray) {
            mGoodsArray.add(model.clone());
        }
        orderID = order;

        mIp = Configure.getConfigData(Configure.CONFIG_PAY_IP);
        try {
            mPort = Integer.parseInt(Configure.getConfigData(Configure.CONFIG_PAY_PORT));
        } catch (NumberFormatException e) {

        }
    }

    public CartTask(final String pOrderNo, final ArrayList<GoodsModel> pGoodsArray, final String pPaytype, final String pDetail) {
        this(pOrderNo, pGoodsArray);
        if (pPaytype != null && !"".equals(pPaytype)) {
            mPaytype = pPaytype;
        }
        if (pDetail != null && !"".equals(pDetail)) {
            mDetail = pDetail;
        }
    }

    public static boolean isProcess() {
        return isProcess;
    }

    @Override
    public void run() {
        isProcess = true;
        if (mGoodsArray == null || mGoodsArray.size() == 0) {
            cleanup(CODE_DATA_ERROR);
            return;
        }
        if (!retryConnect()) {
            cleanup(CODE_NET_ERROR);
            return;
        }
        boolean isReceivePay = false;
        for (int i = 0; i < 120; i++) { // 循环60次，每次间隔1秒询问后台支付状态
            if (!checkConnect()) {
                if (!retryConnect()) {
                    cleanup(CODE_NET_ERROR);
                    return;
                }
            }
            if (!sendPoll()) {
                SystemClock.sleep(500); // 睡眠1秒
                continue;
            }
            if (handlePoll()) {
                isReceivePay = true;
                break;
            }
            SystemClock.sleep(500); // 睡眠1秒
        }
        closeConnect();
        if (isReceivePay) {
            //全部完成
            cleanup(CODE_FINISH);
        } else {
            if (!retryConnect()) {
                cleanup(CODE_NET_ERROR);
                return;
            }
            //查询结果
            if (!sendQuery()) {
                sendTimeout();
                closeConnect();
                cleanup(CODE_FINISH);
            } else {
                handleQuery();
                sendTimeout();
                closeConnect();
                cleanup(CODE_FINISH);
            }
        }
    }

    private void handleQuery() {
        handlePoll();
    }

    private boolean sendQuery() {
        int retry = 3;
        while (retry > 0) {
            if (sendQueryRequest()) {
                return true;
            }
            retry--;
        }
        mLogger.e("send query error");
        return false;
    }

    private boolean sendQueryRequest() {
        StringBuffer data = new StringBuffer();
        data.append("{");
        data.append("\"requeststatus\":\"00\",");
        data.append("\"orderid\":\"").append(orderID).append("\",");
        data.append("\"appid\":\"").append(Configure.getConfigData(Configure.CONFIG_PAY_ID)).append("\",");
//        HashMap<String, String> itemMap = new HashMap<>();
//        itemMap.put("requeststatus", "00");
//        itemMap.put("orderid", orderID);
//        itemMap.put("appid", Configure.getConfigData(Configure.CONFIG_PAY_ID));
        StringBuffer signBuffer = new StringBuffer();
        signBuffer.append("appid=").append(Configure.getConfigData(Configure.CONFIG_PAY_ID)).append("&");
        signBuffer.append("orderid=").append(orderID).append("&");
        signBuffer.append("requeststatus=").append("00");
        data.append("\"sign\":\"").append(getSign(signBuffer.toString())).append("\"");
        data.append("}");
        data.insert(0, "80" + Tools.addLeftZero(String.valueOf(data.length()), 4));
        String sendData = data.toString();
        mLogger.i("send query:" + sendData);
        try {
            out.write(sendData.getBytes());
            out.flush();
        } catch (IOException e) {
            mLogger.e(e.toString());
            return false;
        }
        return true;
    }

    private boolean sendPoll() {
        StringBuffer data = new StringBuffer();
        data.append("{");
        data.append("\"detail\":\"").append(mDetail).append("\",");
        data.append("\"orderid\":\"").append(orderID).append("\",");
        data.append("\"paytype\":\"").append(mPaytype).append("\",");
        data.append("\"requeststatus\":\"01\",");
//        HashMap<String, String> itemMap = new HashMap<>();
//        itemMap.put("requeststatus", "01");
//        itemMap.put("orderid", orderID);
        StringBuffer signBuffer = new StringBuffer();
        signBuffer.append("detail=").append(mDetail).append("&");
        signBuffer.append("orderid=").append(orderID).append("&");
        signBuffer.append("paytype=").append(mPaytype).append("&");
        signBuffer.append("requeststatus=").append("01");
        data.append("\"sign\":\"").append(getSign(signBuffer.toString())).append("\"");
        data.append("}");
        data.insert(0, "80" + Tools.addLeftZero(String.valueOf(data.length()), 4));
        String sendData = data.toString();
        mLogger.i("send poll:" + sendData);
        try {
            out.write(sendData.getBytes());
            out.flush();
        } catch (IOException e) {
            mLogger.e(e.toString());
            return false;
        }
        return true;
    }

    private boolean handlePoll() {
        try {
            //先读取长度
            byte[] buf = new byte[4];
            int r = in.read(buf);
            if (r == -1) {
                throw new IOException("poll read error");
            }
            String sString = new String(buf);
            //mLogger.i("query length:" + sString);
            if ("".equals(sString.trim())) {
                throw new SocketTimeoutException();
            }
            int len;
            try {
                len = Integer.parseInt(sString);
            } catch (NumberFormatException e) {
                throw new IOException("poll read number format error");
            }
            //获取数据
            buf = new byte[len];
            r = in.read(buf);
            int read = r;
            while (read < len) {
                if (r == -1) {
                    throw new IOException("poll read error");
                } else {
                    r = in.read(buf, read, len - read);
                    read += r;
                }
            }
            sString = new String(buf);
            mLogger.i("poll data:" + sString);
            //解析json
            JSONObject object = new JSONObject(sString);
            String code = object.getString("code");
            if (code.equals("01")) {
                mLogger.e("poll sign error");
                return false;
            } else if (code.equals("02")) {
                mLogger.e("poll other error");
                return false;
            } else if (code.equals("00")) {
                //查询成功
                String requeststatus = object.getString("requeststatus");
                String orderid = object.getString("orderid");
                String status = object.getString("status");
                String paytype = object.getString("paytype");
                String detail = object.getString("detail");
                String sign = object.getString("sign");
//                HashMap<String, String> itemMap = new HashMap<>();
//                itemMap.put("requeststatus", requeststatus);
//                itemMap.put("orderid", orderid);
//                itemMap.put("status", status);
//                itemMap.put("paytype", paytype);
//                itemMap.put("code", code);
                StringBuffer signBuffer = new StringBuffer();
                signBuffer.append("code=").append(code).append("&");
                signBuffer.append("detail=").append(detail).append("&");
                signBuffer.append("orderid=").append(orderid).append("&");
                signBuffer.append("paytype=").append(paytype).append("&");
                signBuffer.append("requeststatus=").append(requeststatus).append("&");
                signBuffer.append("status=").append(status);
                if (!checkSign(signBuffer.toString(), sign)) {
                    mLogger.e("poll check sign error");
                    return false;
                }
                if (status.equals("01")) //支付成功
                {
                    return startOutGoods(paytype);
                } else {
                    mLogger.i("poll result:" + status);
                    return false;
                }
            } else {
                mLogger.e("poll unknown result");
                return false;
            }
        } catch (IOException e) {
            mLogger.e(e.toString());
            closeConnect();
            return false;
        } catch (JSONException e) {
            mLogger.e(e.toString());
            return false;
        }
    }
    private boolean startOutGoods(final String pType) {
//        //发06指令
//        if(!sendStart())
//        {
//            return false;
//        }
        String payMethod = DriverThread.OUT_GOODS_WEIXINPAY;
        if (pType.equals("1")) {
            payMethod = DriverThread.OUT_GOODS_WEIXINPAY;
        } else if (pType.equals("2")) {
            payMethod = DriverThread.OUT_GOODS_BAIPAY;
        } else if (pType.equals("3") || pType.equals("4")) {
            payMethod = DriverThread.OUT_GOODS_ALIPAY;
        } else if (pType.equals("6")) { //银联二维码
            payMethod = DriverThread.OUT_GOODS_LF;
        } else if (pType.equals("7")) {
            payMethod = DriverThread.OUT_GOODS_CCB;
        } else if (pType.equals("8")) {
            payMethod = DriverThread.OUT_GOODS_SUNING;
        } else if (pType.equals("e")) { //悦兜支付
            payMethod = DriverThread.OUT_GOODS_TRAVELCARD;
        } else if (pType.equals("g")) {
            payMethod = DriverThread.OUT_GOODS_ALIFACE;
        }else if (pType.equals("b")){
            payMethod = DriverThread.OUT_GOODS_CLOUE_QR;
        }
        sendMessage(CODE_PAY_OK, 0); //通知界面，已经支付完成
        //出货
        int pos = 0;
        int failCount = 0; //出货失败的数量
        for (int i = 0; i < mGoodsArray.size(); i++) {
            GoodsModel model = mGoodsArray.get(i);
            model.setWarranty(0); //使用保质期变量来存储成功失败的数量
            for (int j = 0; j < model.getNum(); j++) {
                pos++;
                sendMessage(CODE_OUT_GOODS, pos); //通知界面正在出第几个商品
                //出单个货
//                SimpleDateFormat sd = new SimpleDateFormat("HHmmss", Locale.US);
//                String tradeTrace = sd.format(new Date());
                String tradeTrace = OrderGenerator.getNextTrace();
                int price = model.getPrice();//元
                if (model.getDiscount() != 100) {
                    int goodsPriceOri = model.getPrice();
                    int goodsPrice = goodsPriceOri * model.getDiscount() / 100;
                    if (goodsPrice < 1) {
                        goodsPrice = 1; //最低1分钱
                    }
                    price = goodsPrice;
                } else {
                    if (price < 1) {
                        price = 1;
                    }
                }
                if (mPaytype.equals(PAYTYPE_ALIFACE)) {
                    //获取人脸支付打折率
                    double alifaceDiscount = Configure.getAlipayDiscount();
                    price = (int) ((double) price * alifaceDiscount / 10.0);
                    if (price < 1) {
                        price = 1;
                    }
                }
                //出货
                if (!DriverThread.getInstance().outGoods(model.getBox(), model.getColumn(), price, payMethod, tradeTrace, orderID)) {
                    //出货失败，发送失败广播
                    failCount++;
                    continue;
                }
                mLogger.i("trace:" + tradeTrace + " orderId:" + orderID);
                int step = 0;
                int result = -1;
                try {
                    while (step <= 120) {
                        Thread.sleep(500);
                        step++;
                        Pair<Integer, Integer> pair = DriverThread.getInstance().getResult(tradeTrace);
                        if (pair != null) {
                            result = pair.first;
                            break;
                        }
                    }
                } catch (InterruptedException e) {
                }
                mLogger.i("out goods result:"+result);
                if (result == 0) { // 出货成功
                    model.setWarranty(model.getWarranty() + 1);
                } else {
                    failCount++;
                }
                SystemClock.sleep(1000);
            }
        }
        //发送出货结果指令
        sendResult();
        sendMessage(CODE_OUT_ALL_GOODS, failCount); //通知界面全部出货完成，告知失败的数量
        return true;
    }

    private void sendResult() {
        int retry = 3;
        while (retry > 0) {
            if (sendResultRequest()) {
                return;
            }
            retry--;
        }
        mLogger.e("send result error");
    }

    private boolean sendResultRequest() {
        if (!checkConnect()) {
            if (!retryConnect()) {
                return false;
            }
        }
        StringBuffer data = new StringBuffer();
        data.append("{");
        data.append("\"requeststatus\":\"").append("09").append("\",");
        data.append("\"orderid\":\"").append(orderID).append("\",");
        data.append("\"paytype\":\"").append(mPaytype).append("\",");
        data.append("\"detail\":\"").append(mDetail).append("\",");
        data.append("\"goodsList\":[");
        for (int i = 0; i < mGoodsArray.size(); i++) {
            GoodsModel model = mGoodsArray.get(i);
            if (i > 0) {
                data.append(",");
            }
            data.append("{");
            data.append("\"goodsid\":\"").append(model.getBarCode()).append("\",");
//            try {
//                data.append("\"goodsname\":\"").append(Base64.encode(model.getName().getBytes("UTF-8"))).append("\",");
//            } catch (UnsupportedEncodingException e) {
//                mLogger.e(e.toString());
//                return false;
//            }
            data.append("\"goodsname\":\"").append(model.getName()).append("\",");
            int price = model.getPrice();
            if (model.getDiscount() != 100) {
                int goodsPriceOri = model.getPrice();
                int goodsPrice = goodsPriceOri * model.getDiscount() / 100;
                if (goodsPrice < 1) {
                    goodsPrice = 1; //最低1分钱
                }
                price = goodsPrice;
            }
            if (mPaytype.equals(PAYTYPE_ALIFACE)) {
                //获取人脸支付打折率
                double alifaceDiscount = Configure.getAlipayDiscount();
                price = (int) ((double) price * alifaceDiscount / 10.0);
                if (price < 1) {
                    price = 1;
                }
            }
            data.append("\"price\":\"").append(String.valueOf(price)).append("\",");
            data.append("\"goodsnum\":\"").append(String.valueOf(model.getNum())).append("\",");
            data.append("\"successnum\":\"").append(String.valueOf(model.getWarranty())).append("\",");
            data.append("\"failnum\":\"").append(String.valueOf(model.getNum() - model.getWarranty())).append("\"");
            data.append("}");
        }
        data.append("]");
//        HashMap<String, String> itemMap = new HashMap<>();
//        itemMap.put("requeststatus", "09");
//        itemMap.put("orderid", orderID);
        StringBuffer signBuffer = new StringBuffer();
        signBuffer.append("detail=").append(mDetail).append("&");
        signBuffer.append("orderid=").append(orderID).append("&");
        signBuffer.append("paytype=").append(mPaytype).append("&");
        signBuffer.append("requeststatus=").append("09");
        data.append(",\"sign\":\"").append(getSign(signBuffer.toString())).append("\"");
        data.append("}");
        try {
            data.insert(0, "80" + Tools.addLeftZero(String.valueOf(data.toString().getBytes("UTF-8").length), 4));
        } catch (UnsupportedEncodingException e) {
            mLogger.e(e.toString());
            return false;
        }
        String sendData = data.toString();
        mLogger.i("send result:" + sendData);
        try {
            out.write(sendData.getBytes());
            out.flush();
        } catch (IOException e) {
            mLogger.e(e.toString());
            return false;
        }
        //接收回复
        return handleRequest();
    }

    private void sendTimeout() {
        int retry = 3;
        while (retry > 0) {
            if (sendRequest("04")) {
                return;
            }
            retry--;
        }
        return;
    }

    private boolean sendStart() {
        int retry = 3;
        while (retry > 0) {
            if (sendRequest("06")) {
                return true;
            }
            retry--;
        }
        return false;
    }

    private boolean sendRequest(final String pRequest) {
        if (!checkConnect()) {
            if (!retryConnect()) {
                return false;
            }
        }
        StringBuffer data = new StringBuffer();
        data.append("{");
        data.append("\"detail\":\"").append(mDetail).append("\",");
        data.append("\"requeststatus\":\"").append(pRequest).append("\",");
        data.append("\"orderid\":\"").append(orderID).append("\",");
//        HashMap<String, String> itemMap = new HashMap<>();
//        itemMap.put("requeststatus", pRequest);
//        itemMap.put("orderid", orderID);
        StringBuffer signBuffer = new StringBuffer();
        signBuffer.append("detail=").append(mDetail).append("&");
        signBuffer.append("orderid=").append(orderID).append("&");
        signBuffer.append("requeststatus=").append(pRequest);
        data.append("\"sign\":\"").append(getSign(signBuffer.toString())).append("\"");
        data.append("}");
        data.insert(0, "80" + Tools.addLeftZero(String.valueOf(data.length()), 4));
        String sendData = data.toString();
        mLogger.i("send:" + pRequest + ":" + sendData);
        try {
            out.write(sendData.getBytes());
            out.flush();
        } catch (IOException e) {
            mLogger.e(e.toString());
            return false;
        }
        //接收回复
        return handleRequest();

    }

    private boolean handleRequest() {
        try {
            //先读取长度
            byte[] buf = new byte[4];
            int r = in.read(buf);
            if (r == -1) {
                throw new IOException("request read error");
            }
            String sString = new String(buf);
            //mLogger.i("query length:" + sString);
            if ("".equals(sString.trim())) {
                throw new SocketTimeoutException();
            }
            int len;
            try {
                len = Integer.parseInt(sString);
            } catch (NumberFormatException e) {
                throw new IOException("request read number format error");
            }
            //获取数据
            buf = new byte[len];
            r = in.read(buf);
            int read = r;
            while (read < len) {
                if (r == -1) {
                    throw new IOException("request read error");
                } else {
                    r = in.read(buf, read, len - read);
                    read += r;
                }
            }
            sString = new String(buf);
            mLogger.i("request data:" + sString);
            //解析json
            JSONObject object = new JSONObject(sString);
            String code = object.getString("code");
            if (code.equals("01")) {
                mLogger.e("request sign error");
                return false;
            } else if (code.equals("02")) {
                mLogger.e("request other error");
                return false;
            } else if (code.equals("00")) {
                //成功
                String requeststatus = object.getString("requeststatus");
                String orderid = object.getString("orderid");
                String detail = object.getString("detail");
                String sign = object.getString("sign");
//                HashMap<String, String> itemMap = new HashMap<>();
//                itemMap.put("requeststatus", requeststatus);
//                itemMap.put("orderid", orderid);
//                itemMap.put("code", code);
                StringBuffer signBuffer = new StringBuffer();
                signBuffer.append("code=").append(code).append("&");
                signBuffer.append("detail=").append(detail).append("&");
                signBuffer.append("orderid=").append(orderid).append("&");
                signBuffer.append("requeststatus=").append(requeststatus);
                if (!checkSign(signBuffer.toString(), sign)) {
                    mLogger.e("request check sign error");
                    return false;
                }
                return true;
            } else {
                mLogger.e("request unknown result");
                return false;
            }
        } catch (IOException e) {
            mLogger.e(e.toString());
            closeConnect();
            return false;
        } catch (JSONException e) {
            mLogger.e(e.toString());
            return false;
        }
    }

//    private String getSign(final HashMap<String, String> pItemMap)
//    {
//        if(pItemMap == null || pItemMap.size() == 0)
//        {
//            return "";
//        }
//        //sort
//        //将map.entrySet()转换成list
//        List<Map.Entry<String, String>> list = new ArrayList<>(pItemMap.entrySet());
//        Collections.sort(list, new Comparator<Map.Entry<String, String>>() {
//            @Override
//            public int compare(Map.Entry<String, String> o1, Map.Entry<String, String> o2) {
//                return o1.getKey().compareTo(o2.getKey());
//            }
//        });
//        StringBuffer data = new StringBuffer();
//        for (Map.Entry<String, String> mapping : list) {
//            if(data.length() > 0)
//            {
//                data.append("&");
//            }
//            data.append(mapping.getKey()).append("=").append(mapping.getValue());
//        }
//        data.append(MD5.md5Encode(KEY));
//        mLogger.i("before sign:" + data.toString());
//        return MD5.md5Encode(data.toString());
//    }

    private String getSign(final String pData) {
        if (pData == null || pData.length() == 0) {
            return "";
        }
        StringBuffer data = new StringBuffer();
        data.append(pData).append(MD5.md5Encode(KEY));
        //mLogger.i("before sign:" + data.toString());
        return MD5.md5Encode(data.toString());
    }

//    private boolean checkSign(final HashMap<String, String> pItemMap, final String pSign)
//    {
//        if(pItemMap == null || pItemMap.size() == 0)
//        {
//            return false;
//        }
//        if(pSign == null || "".equals(pSign))
//        {
//            return false;
//        }
//        String sign = getSign(pItemMap);
//        mLogger.i("my sign:" + sign);
//        mLogger.i("server sign:" + pSign);
//        if(sign.equals(pSign))
//        {
//            return true;
//        }
//        return false;
//    }

    private boolean checkSign(final String pData, final String pSign) {
        if (pData == null || pData.length() == 0) {
            return false;
        }
        if (pSign == null || "".equals(pSign)) {
            return false;
        }
        String sign = getSign(pData);
//        mLogger.i("my sign:" + sign);
//        mLogger.i("server sign:" + pSign);
        if (sign.equals(pSign)) {
            return true;
        }
        return false;
    }

    private void connectServer() throws IOException {
        socket = new Socket();
        socket.setSoTimeout(1000 * 60);
        InetSocketAddress socAddress = new InetSocketAddress(mIp, mPort);
        socket.connect(socAddress, 15000);
        socket.setKeepAlive(true);
        in = socket.getInputStream();
        out = socket.getOutputStream();
    }

    private boolean isConnectSuccess() {
        try {
            connectServer();
        } catch (UnknownHostException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("CartTask " + e.getMessage());
            return false;
        } catch (SocketException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("CartTask " + e.getMessage());
            return false;
        } catch (IOException e) {
            socket = null;
            in = null;
            out = null;
            mLogger.e("CartTask " + e.getMessage());
            return false;
        }
        return true;
    }

    private boolean checkConnect() {
        if (socket != null && in != null && out != null) {
            if (socket.isConnected()) {
                return true;
            } else {
                closeConnect();
                return false;
            }
        } else
            return false;
    }

    private boolean retryConnect() {
        int retry = 3;
        while (retry > 0) {
            if (isConnectSuccess()) {
                return true;
            }
            retry--;
        }
        return false;
    }

    private synchronized void closeConnect() {
        try {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (socket != null) {
                socket.close();
            }
        } catch (IOException e1) {
        }
        socket = null;
        in = null;
        out = null;
    }

    private void cleanup(final int pResultCode) {
        TaskThreadPool.removeIdentifier(getIdentifier());
        if (pResultCode <= 0) {
            sendMessage(pResultCode, 0);
        }
        isProcess = false;
    }

    private void sendMessage(final int pCode, final int pMessage) {
        if (Configure.context != null) {
            Intent intent = new Intent(INTENT_CART_MESSAGE);
            intent.putExtra(EXTRA_CART_CODE, pCode);
            intent.putExtra(EXTRA_CART_MESSAGE, pMessage);
            Configure.context.sendBroadcast(intent);
//            mLogger.i("发送完成");
        }
    }
}
